/*
 * GameObject.h
 *
 *  Created on: 23 Oct 2012
 *      Author: Guy
 */

#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_

#include <string>
#include <list>
#include <tr1/memory>
#include <memory>
#include "core/Component.h"
#include "components/Renderer.h"
#include "core/Object.h"
#include "types/Transform2D.h"
#include "types/Collision.h"

/// SolidityEngine is the main Solidity library namespace
namespace SolidityEngine {

class GameObject;

typedef std::unique_ptr<GameObject> GameObject_ptr;

class GameObject: public Object {
	bool _enabled;
	bool _started;
	bool _deleted;
	std::list<Component_ptr> _components;
    std::string _tag;

public:
	GameObject(const std::string& name="Empty");
	virtual ~GameObject();

	//copy ctor
	GameObject(const GameObject& original);

	template <typename T> T* AddComponent(){
		//create a new component on the heap
        Component* component(new T());
        //set the gameobject parameter of the new component
        component->_gameobject=this;
        //add to the set of components for this gameobject
        _components.push_back(Component_ptr(component));
        //return new component
        return dynamic_cast<T*>(component);
	}

	template <typename T> std::list<T*> GetComponents(){
        std::list<T*> list;
        std::list<Component_ptr>::iterator iter=_components.begin();
        while(iter!=_components.end()){
            T* element=dynamic_cast<T*>(iter->get());
            if(element!=NULL){
                list.push_back(element);
            }
            iter++;
        }
        return list;
    }

    template <typename T> T* GetComponent(){
        std::list<T*> list=GetComponents<T>();
        if(list.size()>0){
            return list.front();
        }
        return NULL;
    }

    std::list<Component*> GetAllComponents(){
        return GetComponents<Component>();
    }

	virtual void Collision(const Collision_ptr& collision); //recieve a collision event

	virtual void Update(); //called every game cycle

    virtual void SetActive(bool flag);

	static GameObject* Instantiate(GameObject* object, const Vector2D& position); //add an clone object

	static void Destroy(GameObject* object);

    static GameObject* Find(const std::string& name);

    static GameObject* FindWithTag(const std::string& tag);

    static std::list<GameObject*> FindGameObjectsWithTag(const std::string& tag);

    bool isDeleted() const {return _deleted;};

    std::string& Tag() {return _tag;};

    std::string Tag() const {return _tag;};

    //Accessor for transform
    Transform2D* Transform() {return this->GetComponent<Transform2D>();};



private:
    virtual GameObject* _Clone(); //overridden clone function
    std::string _Serialize(){
        return std::string("Serialization not implemented for: ")+std::string(typeid(*this).name());
    };
};

} /* namespace SolidCore */
#endif /* GAMEOBJECT_H_ */
